﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows;
using System.Collections;
using System.Reflection;
using System.Linq;
using Mesuro.Common;
using System.ComponentModel;
using Microsoft.Windows.Controls.Ribbon;
using System.Diagnostics;
using Mesuro.Graphing;

namespace Mesuro.GUI {
	[ValueConversion( typeof( bool ), typeof( bool ) )]
	public class BooleanNotConverter : IValueConverter {

		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			return !(bool)value;
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			return !(bool)value;
		}
	}

	[ValueConversion( typeof( Object ), typeof( bool ) )]
	[ValueConversion( typeof( Type ), typeof( bool ) )]
	public class TypeComparator : IValueConverter {

		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			return parameter != null && value != null && ((Type)parameter).IsAssignableFrom( (value as Type) ?? value.GetType() );
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			throw new NotImplementedException();
		}
	}

	[ContentProperty( "Converters" )]
	public class ChainConverter : IValueConverter {

		private readonly List<IValueConverter> _converters = new List<IValueConverter>();

		public List<IValueConverter> Converters {
			get { return _converters; }
		}

		public ChainConverter() { }

		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			object ret = value;
			for (int i = 0; i < Converters.Count; i++)
				ret = Converters[i].Convert( ret, targetType, parameter, culture );
			return ret;
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			object ret = value;
			for (int i = Converters.Count - 1; i >= 0; i--)
				ret = Converters[i].ConvertBack( ret, targetType, parameter, culture );
			return ret;
		}
	}

	[ContentProperty( "List" )]
	[ValueConversion( typeof( Object ), typeof( bool ) )]
	public class CollectionContainsConverter : DependencyObject, IValueConverter {

		#region DP: List
		public static readonly DependencyProperty ListProperty = DependencyProperty.RegisterAttached( "List", typeof( IList ), typeof( CollectionContainsConverter ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None, ListChangedStatic ) );
		public IList List {
			get { return (IList)GetValue( ListProperty ); }
			set { SetValue( ListProperty, value ); }
		}
		public static IList GetList( DependencyObject element ) { return (IList)element.GetValue( ListProperty ); }
		public static void SetList( DependencyObject element, IList value ) { element.SetValue( ListProperty, value ); }
		private static void ListChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		#endregion

		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			IList col = List ?? (parameter as IList);

			if (col == null) return false;

			return col.Contains( value );
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			throw new NotImplementedException();
		}
	}

	public class CollectionIndexMultiConverter : IMultiValueConverter {

		public object Convert( object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			if (values.Length < 2) return null;
			IList list = values[0] as IList;
			if (list != null && values[1] is int)
				return list[(int)values[1]];
			return null;
		}

		public object[] ConvertBack( object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture ) {
			throw new NotImplementedException();
		}
	}
	public class ComparisonConverter : IValueConverter {
		public const string COMP_Eq = "Equal";
		public const string COMP_Ne = "Not Equal";
		public const string COMP_Lt = "Less";
		public const string COMP_Gt = "Greater";
		public const string COMP_Lte = "Less/Equal";
		public const string COMP_Gte = "Greater/Equal";
		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			if (value is string) return value;
			if (value is FilterBuilderComparison)
				switch ((FilterBuilderComparison)value) {
					case FilterBuilderComparison.Equal:
						return COMP_Eq;

					case FilterBuilderComparison.NotEqual:
						return COMP_Ne;

					case FilterBuilderComparison.Less:
						return COMP_Lt;

					case FilterBuilderComparison.Greater:
						return COMP_Gt;

					case FilterBuilderComparison.LessEqual:
						return COMP_Lte;

					case FilterBuilderComparison.GreaterEqual:
						return COMP_Gte;

				}
			return null;
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			if (value is FilterBuilderComparison) return value;
			if (value is string)
				switch ((string)value) {
					case COMP_Eq:
						return FilterBuilderComparison.Equal;
					case COMP_Ne:
						return FilterBuilderComparison.NotEqual;
					case COMP_Lt:
						return FilterBuilderComparison.Less;
					case COMP_Gt:
						return FilterBuilderComparison.Greater;
					case COMP_Lte:
						return FilterBuilderComparison.LessEqual;
					case COMP_Gte:
						return FilterBuilderComparison.GreaterEqual;
				}
			return null;
		}
	}
	public class AxesSpecificOptionsConverter : IValueConverter {

		public static FrameworkElement createEditor( UserPropertyAttribute att, object bindingSource ) {
			TypeConverter conv = (att.Converter != null) ? (TypeConverter)att.Converter.GetConstructor( System.Type.EmptyTypes ).Invoke( null ) : new TypeConverter();
			Binding binding = new Binding( att.PropertyName ) { Source = bindingSource, Mode = BindingMode.TwoWay, Converter = conv as IValueConverter };
			return createEditorImpl( att, binding, conv );
		}

		public static System.Windows.Controls.Control createEditorImpl( UserPropertyAttribute att, Binding binding, TypeConverter conv ) {
			System.Windows.Controls.Control ctrl;
			if (att.AsCheckBox) {
				RibbonCheckBox cb = new RibbonCheckBox();
				cb.Label = att.Label;
				cb.IsThreeState = att.CheckboxThreeState;
				cb.SetBinding( RibbonCheckBox.IsCheckedProperty, binding );
				ctrl = cb;
			} else if (conv.GetStandardValuesSupported()) {
				RibbonComboBox cb = new RibbonComboBox();
				cb.Label = att.Label;
				cb.IsEditable = true;

				RibbonGallery gal = new RibbonGallery();
				RibbonGalleryCategory cat = new RibbonGalleryCategory();

				cat.ItemsSource = conv.GetStandardValues();

				gal.Items.Add( cat );
				cb.Items.Add( gal );

				BindingExpressionBase exp = gal.SetBinding( RibbonGallery.SelectedValueProperty, binding );
				PresentationTraceSources.SetTraceLevel( exp, PresentationTraceLevel.High );
				ctrl = cb;
			} else {
				RibbonTextBox tb = new RibbonTextBox();

				tb.Label = att.Label;
				BindingExpressionBase exp = tb.SetBinding( RibbonTextBox.TextProperty, binding );
				PresentationTraceSources.SetTraceLevel( exp, PresentationTraceLevel.High );
				ctrl = tb;
			}
			return ctrl;
		}

		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			return value.GetType().GetCustomAttributes( typeof( Mesuro.Graphing.AxisPropertyAttribute ), true ).Select( o => createEditor( o as Mesuro.Graphing.UserPropertyAttribute, parameter ?? value ) );
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			throw new NotImplementedException();
		}
	}
	public class PlotSpecificOptionsConverter : IValueConverter {
		private static PropertyPathConverter ppconv = new PropertyPathConverter();

		public static FrameworkElement createEditor( Mesuro.Graphing.UserPropertyAttribute att, object bindingSource, Type attachTo ) {
			TypeConverter conv = (att.Converter != null) ? (TypeConverter)att.Converter.GetConstructor( System.Type.EmptyTypes ).Invoke( null ) : new TypeConverter();
			Binding binding = new Binding() {Path=new PropertyPath(attachTo.GetField( att.PropertyName + "Property").GetValue( null )), Source = bindingSource, Mode = BindingMode.TwoWay, Converter = conv as IValueConverter };
			return AxesSpecificOptionsConverter.createEditorImpl( att, binding, conv );
		}

		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			return (value==null)? null:value.GetType().GetCustomAttributes( typeof( Mesuro.Graphing.PlotPropertyAttribute ), true ).Select( o => createEditor( o as Mesuro.Graphing.UserPropertyAttribute, parameter ?? value, value.GetType() ) );
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			throw new NotImplementedException();
		}
	}
	[ValueConversion( typeof( ICollection ), typeof( bool ) )]
	public class CollectionIsEmptyConverter : IValueConverter {
		public ICollection Collection { get; set; }

		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			ICollection c = (value as ICollection) ?? Collection;
			if (c == null) return true;
			return c.Count == 0;
		}

		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) {
			throw new NotImplementedException();
		}
	}
}
